// 版权所有2011 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件包含CRC32算法，这些算法不特定于任何体系结构
// 并且不使用硬件加速。
// 
// 简单（且缓慢）的CRC32实现只使用256*4字节的表。
// 
// 8分片算法是一种更快的实现，它使用更大的
// 表（8*256*4字节）。

package crc32

// simpleMakeTable为指定的
// 多项式分配和构造一个表。该表适用于简单算法
// /（simpleUpdate）。
func simpleMakeTable(poly uint32) *Table {
	t := new(Table)
	simplePopulateTable(poly, t)
	return t
}

// simplePopulateTable为指定的多项式构造一个表，适合与simpleUpdate一起使用。
func simplePopulateTable(poly uint32, t *Table) {
	for i := 0; i < 256; i++ {
		crc := uint32(i)
		for j := 0; j < 8; j++ {
			if crc&1 == 1 {
				crc = (crc >> 1) ^ poly
			} else {
				crc >>= 1
			}
		}
		t[i] = crc
	}
}

// simpleUpdate使用simple算法更新CRC，前提是
// 以前是使用SimpleTable计算的表。
func simpleUpdate(crc uint32, tab *Table, p []byte) uint32 {
	crc = ^crc
	for _, v := range p {
		crc = tab[byte(crc)^v] ^ (crc >> 8)
	}
	return ^crc
}

// 当有效负载>=此值时，使用8倍切片。
const slicing8Cutoff = 16

// slicing8Table是由8个表组成的数组，用于按8切片算法。
type slicing8Table [8]Table

// SlicingTable为指定的多项式构造Slicing8表。
// 表格适用于8次切片算法（slicingUpdate）。
func slicingMakeTable(poly uint32) *slicing8Table {
	t := new(slicing8Table)
	simplePopulateTable(poly, &t[0])
	for i := 0; i < 256; i++ {
		crc := t[0][i]
		for j := 1; j < 8; j++ {
			crc = t[0][crc&0xFF] ^ (crc >> 8)
			t[j][i] = crc
		}
	}
	return t
}

// slicingUpdate使用8分片算法来更新CRC，给定一个先前使用SlicingTable计算的
// 表。
func slicingUpdate(crc uint32, tab *slicing8Table, p []byte) uint32 {
	if len(p) >= slicing8Cutoff {
		crc = ^crc
		for len(p) > 8 {
			crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
			crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^
				tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^
				tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF]
			p = p[8:]
		}
		crc = ^crc
	}
	if len(p) == 0 {
		return crc
	}
	return simpleUpdate(crc, &tab[0], p)
}
